using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using Magiq.Databases.SqlServer;
using Magiq.Support;
using Magiq.Support.DynamicClasses;

namespace Magiq.Databases.Update
{
    public class UpdateCommandBuilder : DynamicSelectCommandBuilder
    {
        private readonly UpdateColumnsAssignment sampleColumnsAssignment;

        public UpdateCommandBuilder(IOrmAdapter ormAdapter, IQueryable where,
                                    IEnumerable<UpdateColumnsAssignment> columnAssignments)
            : base(ormAdapter, where, columnAssignments.Cast<ColumnsAssignment>(), true)
        {
            sampleColumnsAssignment = columnAssignments.First();
            Init(sampleColumnsAssignment.DeclaringType);
        }

        private void ProcessTypeReferenceBinding()
        {
            var expression = sampleColumnsAssignment.PropertyExpression.PreviousExpressionChain(true).Body;
            var typeReferenceExpression = Expression.Property(expression.ChangeParameter(Parameter),
                                                              TypeReferenceProperty.PropertyName);

            Bindings.Add(Expression.Bind(DynamicClass.GetProperty(TypeReferenceName), typeReferenceExpression));
        }

        protected override List<DynamicProperty> CreateDynamicProperties()
        {
            var properties = base.CreateDynamicProperties();
            properties.Insert(0, new DynamicProperty(TypeReferenceName, TypeReferenceProperty.Type));
            return properties;
        }

        protected override IEnumerable<string> GetCalculatedSqlValues()
        {
            return base.GetCalculatedSqlValues().Skip(1);
        }

        protected override void OnDynamicClassForSelectBuilt()
        {
            ProcessTypeReferenceBinding();
        }

        public override IDbCommand GetCommand()
        {
            var values = BaseSelectedValues;
            var sets = new Dictionary<string, string>();

            var columns = Columns;

            for (var i = 0; i < values.Length; i++)
                sets.Add(columns[i], values[i]);

            Command.CommandText = OrmAdapter.Dialect.UpdateClauseFor(BaseTableName, sets, From);
            return Command;
        }
    }
}